package com.own.component.token.jwt.base;

import com.own.component.common.exception.BusinessException;
import com.own.component.common.util.encrypt.EncryptUtil;
import com.own.component.common.util.encrypt.model.CustomEncryptKey;
import com.own.component.store.core.Store;
import com.own.component.store.core.method.StoreSet;
import com.own.component.store.core.method.StoreValue;
import com.own.component.token.base.AbstractStoreTokenManager;
import com.own.component.token.base.StoreTokenManager;
import com.own.component.token.base.TokenBuildPolicy;
import com.own.component.token.jwt.property.TokenJwtProperty;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.context.annotation.Bean;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.UUID;

/**
 * DefaultTokenJwtConfig
 *
 * @author chenxueli
 * @date 2023-11-07 19:49:54
 */
@Slf4j
@SpringBootConfiguration
public class DefaultTokenJwtConfig {

    private static final String TOKEN_PRIVATE_KEY = "TOKEN:PRIVATE:KEY";
    private static final String TOKEN_PUBLIC_KEY = "TOKEN:PUBLIC:KEY";
    @Resource
    public TokenBuildPolicy tokenBuildPolicy;
    @Resource
    public StoreSet<String> tokenStore;
    @Resource
    public StoreValue<String> userIdStore;
    @Resource
    private Store<String> store;
    @Resource
    private TokenJwtProperty tokenJwtProperty;

    @PostConstruct
    public void init() {
        // 判断有没有对应的参数
        if (StringUtils.isNotBlank(tokenJwtProperty.getPrivateKey()) && StringUtils.isNotBlank(tokenJwtProperty.getPublicKey())) {
            // 验证公私钥是否正确
            var text = UUID.randomUUID().toString();
            var key = CustomEncryptKey.builder()
                    .publicKey(tokenJwtProperty.getPublicKey())
                    .privateKey(tokenJwtProperty.getPrivateKey())
                    .build();
            // 公钥加密
            var encrypt = EncryptUtil.RSA.encrypt(text, key);
            // 私钥解密
            var decrypt = EncryptUtil.RSA.decrypt(encrypt, key);
            if (StringUtils.equals(text, decrypt)) {
                log.debug("导入配置文件文件中的jwt-key");
                store.value().set(TOKEN_PRIVATE_KEY, tokenJwtProperty.getPrivateKey());
                store.value().set(TOKEN_PUBLIC_KEY, tokenJwtProperty.getPublicKey());
                return;
            }
            throw new BusinessException("公私钥不匹配");
        }
        if (store.contains(TOKEN_PRIVATE_KEY) && store.contains(TOKEN_PUBLIC_KEY)) {
            return;
        }
        // 创建新的key，非必要不要手动清除
        var key = EncryptUtil.RSA.buildKey();
        log.info("jwt-key生成的公钥为：{}", key.getPublicKey());
        log.info("jwt-key生成的私钥为：{}", key.getPrivateKey());
        store.value().set(TOKEN_PRIVATE_KEY, key.getPrivateKey());
        store.value().set(TOKEN_PUBLIC_KEY, key.getPublicKey());
    }

    @Bean
    public StoreTokenManager storeTokenManager() {
        return new AbstractStoreTokenManager(
                tokenStore,
                userIdStore,
                tokenBuildPolicy
        ) {
            @Override
            public boolean checkToken(String token) {
                try {
                    EncryptUtil.RSA.decrypt(token, CustomEncryptKey.builder().privateKey(store.value().get(TOKEN_PRIVATE_KEY)).build());
                    return super.checkToken(token);
                } catch (Exception e) {
                    return false;
                }
            }

            @Override
            public Long getUserId(String token) {
                var content = EncryptUtil.RSA.decrypt(token, CustomEncryptKey.builder().privateKey(store.value().get(TOKEN_PRIVATE_KEY)).build());
                return Long.parseLong(content.split("&")[0]);
            }
        };
    }

    @Bean
    public TokenBuildPolicy tokenBuildPolicy() {
        return (userId, client) -> {
            var timestamp = System.currentTimeMillis();
            var content = String.join("&", userId + "", client, timestamp + "");
            return EncryptUtil.RSA.encrypt(content, CustomEncryptKey.builder().publicKey(store.value().get(TOKEN_PUBLIC_KEY)).build());
        };
    }

}
